#include "baseplugin.hpp"
#include <sstream>
#include<iomanip>

#include <Pluma/Connector.hpp>

/////////////////////////////////////////////////////////
/// Plugin connects to hosts through this function
/// Add Eagle and Jaguar providers to the host, so that it
/// can create and use those kind of warriors
/////////////////////////////////////////////////////////
PLUMA_CONNECTOR
bool connect(pluma::Host& host){
    host.add( new Request1Provider() );
    return true;
}


void Request1::processImage(const HObject &ho_image, HalconResult &result)
{
    // Local iconic variables
    HObject  ho_ROI_0, ho_ImageReduced;
    HObject  ho_BrightRegion, ho_OpeningCircle, ho_ConnectedRegions;
    HObject  ho_SmallBallCandidateRegions, ho_SmallBallRegions;
    HObject  ho_SortedSmallBallRegions, ho_RegionDifference;
    HObject  ho_SelectedRegions, ho_BigBallRegions, ho_SortedBigBallRegions;

    // Local control variables
    HTuple  hv_WindowHandle, hv_mmPerPixel, hv_RowSmallBall;
    HTuple  hv_ColumnSmallBall, hv_RadiusSmallBall, hv_RowBigBall;
    HTuple  hv_ColumnBigBall, hv_RadiusBigBall, hv_Distance;
    HTuple  hv_RealDistance;


    hv_mmPerPixel = 0.03;

    GenRectangle1(&ho_ROI_0, 258, 766, 412, 1828);
    ReduceDomain(ho_image, ho_ROI_0, &ho_ImageReduced);

    Threshold(ho_ImageReduced, &ho_BrightRegion, 255, 255);
    OpeningCircle(ho_BrightRegion, &ho_OpeningCircle, 3.5);

    Connection(ho_OpeningCircle, &ho_ConnectedRegions);
    SelectShape(ho_ConnectedRegions, &ho_SmallBallCandidateRegions, "roundness", "and",
                0.9, 0.99);

    ShapeTrans(ho_SmallBallCandidateRegions, &ho_SmallBallRegions, "outer_circle");
    SortRegion(ho_SmallBallRegions, &ho_SortedSmallBallRegions, "character", "true",
               "col");
    SmallestCircle(ho_SortedSmallBallRegions, &hv_RowSmallBall, &hv_ColumnSmallBall,
                   &hv_RadiusSmallBall);


    Difference(ho_ConnectedRegions, ho_SmallBallCandidateRegions, &ho_RegionDifference
               );
    SelectShape(ho_ConnectedRegions, &ho_SelectedRegions, "height", "and", 50, 300);
    ShapeTrans(ho_SelectedRegions, &ho_BigBallRegions, "outer_circle");
    SortRegion(ho_BigBallRegions, &ho_SortedBigBallRegions, "character", "true", "col");
    SmallestCircle(ho_SortedBigBallRegions, &hv_RowBigBall, &hv_ColumnBigBall, &hv_RadiusBigBall);


    DistancePp(hv_RowSmallBall, hv_ColumnSmallBall, hv_RowBigBall, hv_ColumnBigBall,
               &hv_Distance);

    hv_RealDistance = hv_Distance*hv_mmPerPixel;


    // transfer the results
    long numBigBalls = hv_RowBigBall.Length();

    for(int i=0; i<numBigBalls;i++){
        CircleMark mark;
        mark.centerX = hv_ColumnBigBall[i].D();
        mark.centerY = hv_RowBigBall[i].D();
        mark.radius = hv_RadiusBigBall[i].D();

        double distance = hv_RealDistance[i].D();
        if(distance >0.15){
            mark.ifWrong = true;
        } else {
            mark.ifWrong = false;
        }

        std::ostringstream os;
        os<<std::fixed<<std::setprecision(3)<<distance;

        mark.note = os.str();

        result.circleMarkVector.push_back(mark);
    }

    long numSmallBalls = hv_RowSmallBall.Length();
    for(int i=0; i<numBigBalls;i++){
        CircleMark mark;
        mark.centerX = hv_ColumnSmallBall[i].D();
        mark.centerY = hv_RowSmallBall[i].D();
        mark.radius = hv_RadiusSmallBall[i].D();

        double distance = hv_RealDistance[i].D();
        if(distance >0.15){
            mark.ifWrong = true;
        } else {
            mark.ifWrong = false;
        }

        result.circleMarkVector.push_back(mark);
    }
}



